/*
 *Copyright (c) [2019-2020]  C2comm, Inc.  All rights reserved.
 *
 *This program is free software; you can redistribute it and/or
 *modify it under the terms of the GNU General Public License
 *as published by the Free Software Foundation; either version 2
 *of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful,
 *but WITHOUT ANY WARRANTY; without even the implied warranty of
 *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License
 *along with this program; If not, see <https://www.gnu.org/licenses/>
 */

/*
 *Vendor: C2comm
 *Version: 1.0
 *Filename: CompressCtrl.v
 *Target Device: Altera
 *Author : 刘晓骏
*/

module CompressCtrl #(
    parameter  FAULT_TOLERANT_NUM = 1
)(
    input  wire         SYS2CORE_clk,
    input  wire         SYS2CORE_rst_n,
                
    input  wire [336:0] CONF2CORE_cm_static_conf,
                
    output reg          CC2PP_compress_end,
                
    input  wire         PP2CC_pcf_rx_cb_wrreq,
    input  wire [85:0]  PP2CC_pcf_rx_cb,
    output reg          CC2PP_pcf_rx_cb_wrack,
                
    output reg          CC2PD_pcf_rx_cb_wr,
    output reg  [85:0]  CC2PD_pcf_rx_cb,
    input  wire         PD2CC_pcf_rx_cb_ready
);
/*//////////////////////////////////////////////////////////
                    中间变量声明区域
*///////////////////////////////////////////////////////////
//本模块中所有中间变量(wire/reg/parameter)在此集中声明 
reg  [19:0] collect_gapcnt;//检测每两个pcf_rx_cb之间的间隔时间
wire [19:0] next_collect_gapcnt;

reg         calc_relative_valid;
reg  [67:0] calc_relative;

reg  [ 3:0] collect_cnt;

reg  [67:0] cur_collect_permnt_pit [6:0];
reg  [67:0] nxt_collect_permnt_pit [6:0];


reg  [67:0] max_collect_permnt_pit;
reg  [67:0] min_collect_permnt_pit;


reg  [67:0] calc_compress_corr;

reg         collect_timeout;
reg  [47:0] max_ob_endpit;

reg  [47:0] allow_max_pit;


reg  [ 2:0] compress_state;

localparam  IDLE_S    = 3'b001,
            COLLECT_S = 3'b010,
            SEND_S    = 3'b100;

/*//////////////////////////////////////////////////////////
            收集窗口判断(CollectWindowJudge)
*///////////////////////////////////////////////////////////
assign next_collect_gapcnt = collect_gapcnt + 1'b1;

always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        collect_gapcnt <= 20'b0;
        collect_timeout <= 1'b0;
    end
    else if((compress_state == IDLE_S) && (PP2CC_pcf_rx_cb_wrreq == 1'b1)) begin
            collect_gapcnt <= 20'b0;
            collect_timeout <= 1'b0;
        end
    else begin
        if(next_collect_gapcnt == CONF2CORE_cm_static_conf[208:189]) begin
            collect_gapcnt  <= collect_gapcnt;
            collect_timeout <= 1'b1;
        end
        else begin
            collect_gapcnt <= next_collect_gapcnt;
            collect_timeout <= 1'b0;
        end
    end
end


/*//////////////////////////////////////////////////////////
            PCF帧收集(ResultTrans)
*///////////////////////////////////////////////////////////
always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
    if(SYS2CORE_rst_n == 1'b0) begin
        CC2PP_compress_end    <= 1'b0;
        
        CC2PP_pcf_rx_cb_wrack <= 1'b0;
        CC2PD_pcf_rx_cb_wr    <= 1'b0;
        
        calc_relative_valid   <= 1'b0;
        collect_cnt           <= 4'b0;
        
        compress_state        <= IDLE_S;
    end
    else begin
        case(compress_state)
            IDLE_S: begin
                CC2PP_compress_end    <= 1'b0;
                CC2PD_pcf_rx_cb_wr    <= 1'b0;
                
                calc_relative_valid   <= 1'b0;
                collect_cnt           <= 4'd0;
                if(PP2CC_pcf_rx_cb_wrreq == 1'b1) begin
             
                    CC2PP_pcf_rx_cb_wrack <= 1'b1;
                    max_ob_endpit         <= PP2CC_pcf_rx_cb[85:38]+CONF2CORE_cm_static_conf[228:209];
                    allow_max_pit         <= PP2CC_pcf_rx_cb[85:38]+CONF2CORE_cm_static_conf[208:189];
                  
                    CC2PD_pcf_rx_cb       <= PP2CC_pcf_rx_cb;
                    compress_state        <= COLLECT_S;
                end
                else begin
                    CC2PP_pcf_rx_cb_wrack <= 1'b0;
                    compress_state        <= IDLE_S;
                end
            end
            
            COLLECT_S: begin
                if(collect_timeout == 1'b1) begin
         
                    CC2PP_pcf_rx_cb_wrack <= 1'b0;
                    calc_relative_valid   <= 1'b0;
                    compress_state        <= SEND_S;
                end
                else begin
                    if(PP2CC_pcf_rx_cb_wrreq == 1'b1) begin
                        if((PP2CC_pcf_rx_cb[85:38]>max_ob_endpit) || 
                           (PP2CC_pcf_rx_cb[85:38]>allow_max_pit)) begin
                           
                            CC2PP_pcf_rx_cb_wrack <= 1'b0;
                            calc_relative_valid   <= 1'b0;
                            compress_state        <= SEND_S;
                        end
                        else begin
                            CC2PP_pcf_rx_cb_wrack <= 1'b1;
                            calc_relative_valid   <= 1'b1;

                          
                            calc_relative[67:20] <= PP2CC_pcf_rx_cb[85:38] - CC2PD_pcf_rx_cb[85:38];
                            calc_relative[19: 0] <= PP2CC_pcf_rx_cb[37:18] - CC2PD_pcf_rx_cb[37:18];
                            
                            collect_cnt          <= collect_cnt + 1'b1;
                           
                            CC2PD_pcf_rx_cb[15:8] <= CC2PD_pcf_rx_cb[15:8] | PP2CC_pcf_rx_cb[15:8];
                            
                           
                            allow_max_pit         <= PP2CC_pcf_rx_cb[85:38]+CONF2CORE_cm_static_conf[208:189];

                            compress_state        <= COLLECT_S;
                        end
                    end
                    else begin
                        CC2PP_pcf_rx_cb_wrack <= 1'b0;
                        calc_relative_valid   <= 1'b0;
                        compress_state        <= COLLECT_S;
                    end
                end
            end

            SEND_S: begin
                CC2PP_pcf_rx_cb_wrack <= 1'b0;
                if(PD2CC_pcf_rx_cb_ready == 1'b1) begin
                    CC2PP_compress_end    <= 1'b1;
                    CC2PD_pcf_rx_cb_wr    <= 1'b1;
                    CC2PD_pcf_rx_cb[85:38] <=  CC2PD_pcf_rx_cb[85:38] + 
                                               calc_compress_corr[67:20] + 
                                               CONF2CORE_cm_static_conf[228:209] + 
                                               CONF2CORE_cm_static_conf[334:315];
                    CC2PD_pcf_rx_cb[37:18] <=  CC2PD_pcf_rx_cb[37:18] + 
                                               calc_compress_corr[19:0] + 
                                               CONF2CORE_cm_static_conf[228:209] + 
                                               CONF2CORE_cm_static_conf[334:315];
                   
                    compress_state        <= IDLE_S;
                end
                else begin
                    CC2PP_compress_end    <= 1'b0;
                    CC2PD_pcf_rx_cb_wr    <= 1'b0;
                    compress_state        <= SEND_S;
                end
            end
            default: begin
                CC2PP_compress_end    <= 1'b0;
                
                CC2PP_pcf_rx_cb_wrack <= 1'b0;
                CC2PD_pcf_rx_cb_wr    <= 1'b0;
                
                compress_state        <= IDLE_S;
            end
        endcase
    end
end

/*//////////////////////////////////////////////////////////
            压缩计算(CompressCalc)
*///////////////////////////////////////////////////////////


generate
    genvar i;
    for(i=1;i<8;i=i+1) begin:store_relative
        always @* begin
            if((calc_relative_valid == 1'b1) && (collect_cnt == i))
                nxt_collect_permnt_pit[i-1] = calc_relative;
            else
                nxt_collect_permnt_pit[i-1] = cur_collect_permnt_pit[i-1];
        end
        
        always @(posedge SYS2CORE_clk or negedge SYS2CORE_rst_n) begin
            if(SYS2CORE_rst_n == 1'b0)
                cur_collect_permnt_pit[i-1] <= 68'b0;
            else
                cur_collect_permnt_pit[i-1] <= nxt_collect_permnt_pit[i-1];
        end
    end
endgenerate   


always @* begin
    case(collect_cnt)
        4'd0: begin 
            calc_compress_corr[67:20] =  48'b0;
            calc_compress_corr[19: 0] =  20'b0;
        end 
        
        4'd1: begin
            calc_compress_corr[67:20] = nxt_collect_permnt_pit[0][67:21] + 
                                        nxt_collect_permnt_pit[0][20];                    
            calc_compress_corr[19: 0] = nxt_collect_permnt_pit[0][19: 1] + 
                                        nxt_collect_permnt_pit[0][ 0];
        end   

        4'd2: begin
            calc_compress_corr[67:20] = nxt_collect_permnt_pit[0][67:20];                    
            calc_compress_corr[19: 0] = nxt_collect_permnt_pit[0][19: 0];
        end         
        
        4'd3: begin
            calc_compress_corr[67:20] = nxt_collect_permnt_pit[0][67:21] + 
                                        nxt_collect_permnt_pit[1][67:21] + 
                                       (nxt_collect_permnt_pit[0][   20] | nxt_collect_permnt_pit[1][   20]);                 
            calc_compress_corr[19: 0] = nxt_collect_permnt_pit[0][19: 1] + 
                                        nxt_collect_permnt_pit[1][19: 1] + 
                                       (nxt_collect_permnt_pit[0][    0] | nxt_collect_permnt_pit[1][    0]);
        end  
        
        4'd4: begin
            calc_compress_corr[67:20] = nxt_collect_permnt_pit[0][67:21] + 
                                        nxt_collect_permnt_pit[2][67:21] + 
                                       (nxt_collect_permnt_pit[0][   20] | nxt_collect_permnt_pit[2][   20]);                 
            calc_compress_corr[19: 0] = nxt_collect_permnt_pit[0][19: 1] + 
                                        nxt_collect_permnt_pit[2][19: 1] + 
                                       (nxt_collect_permnt_pit[0][    0] | nxt_collect_permnt_pit[2][    0]);
        end
        
        default: begin
            calc_compress_corr[67:20] = max_collect_permnt_pit[67:21] + 
                                        min_collect_permnt_pit[67:21] + 
                                       (max_collect_permnt_pit[   20] | min_collect_permnt_pit[   20]);                 
            calc_compress_corr[19: 0] = max_collect_permnt_pit[19: 1] + 
                                        min_collect_permnt_pit[19: 1] + 
                                       (max_collect_permnt_pit[    0] | min_collect_permnt_pit[    0]);
        end
    endcase
end



always @* begin
    if     (FAULT_TOLERANT_NUM == 0) begin
        max_collect_permnt_pit = nxt_collect_permnt_pit[  0];
        min_collect_permnt_pit = nxt_collect_permnt_pit[6-0];
    end
    else if(FAULT_TOLERANT_NUM == 1) begin
        max_collect_permnt_pit = nxt_collect_permnt_pit[  1];
        min_collect_permnt_pit = nxt_collect_permnt_pit[6-1];
    end
    else if(FAULT_TOLERANT_NUM == 2) begin
        max_collect_permnt_pit = nxt_collect_permnt_pit[  2];
        min_collect_permnt_pit = nxt_collect_permnt_pit[6-2];
    end
    else begin
        max_collect_permnt_pit = nxt_collect_permnt_pit[  3];
        min_collect_permnt_pit = nxt_collect_permnt_pit[6-3];
    end
end

/*//////////////////////////////////////////////////////////
                        IP调用区域
*///////////////////////////////////////////////////////////
//本模块调用的所有IP在该区域实例化
//例如fifo/ram/grant之类的IP.... 

endmodule
/*
CompressCtrl CompressCtrl_inst(
    .SYS2CORE_clk(),
    .SYS2CORE_rst_n(),

    .CONF2CORE_cm_static_conf(),

    .CC2PP_compress_end(),

    .PP2CC_pcf_rx_cb_wrreq(),
    .PP2CC_pcf_rx_cb(),
    .CC2PP_pcf_rx_cb_wrack(),

    .CC2PD_pcf_rx_cb_wr(),
    .CC2PD_pcf_rx_cb(),
    .PD2CC_pcf_rx_cb_ready()
);
*/